#ifndef __MY_DATA__
#define __MY_DATA__

#include "util.hpp"
#include <cstdlib>
#include <mutex>
#include <mysql/mysql.h>

namespace vod
{
#define HOST "127.0.0.1"
#define USER "root"
#define PASS "@Aa123456"
#define NAME "vod_system"
    // 初始化mysql，并与mysql进行链接
    static MYSQL *MysqlInit()
    {
        // 初始化
        MYSQL *mysql = mysql_init(nullptr);
        if(mysql == nullptr)
        {
            std::cout << "init mysql instance failed\n";
            return nullptr;
        }
        // 链接mysql
        if(mysql_real_connect(mysql, HOST, USER, PASS, NAME, 0, nullptr, 0) == nullptr)
        {
            std::cout << "connect mysql server failed\n";
            mysql_close(mysql);
            return nullptr;
        }
        // 初始化字符集utf8
        mysql_set_character_set(mysql, "utf8");
        // 返回初始化好的mysql
        return mysql;
    }

    // 销毁mysql
    static void MysqlDestroy(MYSQL *mysql)
    {
        if(mysql != nullptr) mysql_close(mysql);
        return;
    }

    // mysql查询
    static bool MysqlQuery(MYSQL *mysql, const std::string &sql)
    {
        int ret = mysql_query(mysql, sql.c_str());
        if(ret != 0)
        {
            std::cout << sql << std::endl;
            std::cout << mysql_error(mysql) << std::endl;
            return false;
        }
        return true;
    }

    class TableVideo
    {
    public:
        // mysql初始化
        TableVideo()
        {
            mysql_ = MysqlInit();
            if(mysql_ == nullptr) exit(-1);
        }
        // mysql销毁
        ~TableVideo()
        {
            MysqlDestroy(mysql_);
        }

        // 对mysql进行插入操作
        bool Insert(const Json::Value &video)
        {
            std::string sql;
            // 防止简介过长
            sql.resize(4096 + video["info"].asString().size());
            #define INSERT_VIDEO "insert tb_video values(null, '%s', '%s', '%s', '%s');"
            // 需要更细致的完成对各个数据进行校验, 因为不校验直接用可能会出问题
            if(video["name"].asString().size() == 0)
            {
                return false;
            }
            sprintf(&sql[0], INSERT_VIDEO, video["name"].asCString(),
                    video["info"].asCString(),
                    video["video"].asCString(),
                    video["image"].asCString());
            return MysqlQuery(mysql_, sql);
        }

        // 对mysql进行更新操作
        bool Update(int video_id, const Json::Value &video)
        {
            std::string sql;
            sql.resize(4096 + video["info"].asString().size());
            #define UPDATE_VIDEO "update tb_video set name='%s', info='%s' where id=%d;"
            sprintf(&sql[0],UPDATE_VIDEO, video["name"].asCString(),
                    video["info"].asCString(), video_id);
            return MysqlQuery(mysql_, sql);
        }

        // 对mysql进行删除操作
        bool Delete(int video_id)
        {
            #define DELETE_VIDEO "delete from tb_video where id=%d;"
            char sql[1024] = {0};
            sprintf(sql, DELETE_VIDEO, video_id);
            return MysqlQuery(mysql_, sql);
        }
        
        // 对mysql进行查询全部操作
        bool SelectAll(Json::Value *videos)
        {
            #define SELECTALL_VIDEO "select * from tb_video;"
            // 保护查询与保存结果到本地的过程
            mutex_.lock();
            // 查询
            bool ret = MysqlQuery(mysql_, SELECTALL_VIDEO);
            if(ret == false)
            {
                mutex_.unlock();
                return false;
            }
            // 获取查询结果集
            MYSQL_RES *res = mysql_store_result(mysql_);
            if(res == nullptr)
            {
                std::cout << "mysql store result failed\n";
                mutex_.unlock();
                return false;
            }
            mutex_.unlock();
            // 获取结果集的行数
            int num_rows = mysql_num_rows(res);
            for(int i = 0; i < num_rows; ++i)
            {
                // 获取结果集的行内容
                MYSQL_ROW row = mysql_fetch_row(res);
                Json::Value video;
                video["id"] = atoi(row[0]);
                video["name"] = row[1];
                video["info"] = row[2];
                video["video"] = row[3];
                video["image"] = row[4];
                // 插入到videos中
                videos->append(video);
            }

            // 自动释放内存
            mysql_free_result(res);
            return true;
        }

        // 对mysql进行查询一个操作
        bool SelectOne(int video_id, Json::Value *video)
        {
            #define SELECTONE_VIDEO "select * from tb_video where id=%d;"
            char sql[1024] = {0};
            sprintf(sql, SELECTONE_VIDEO, video_id);
            // 保护查询与保存结果到本地的过程
            mutex_.lock();
            // 查询
            bool ret = MysqlQuery(mysql_, sql);
            if(ret == false)
            {
                mutex_.unlock();
                return false;
            }
            // 获取查询结果集
            MYSQL_RES *res = mysql_store_result(mysql_);
            if(res == nullptr)
            {
                std::cout << "mysql store result failed\n";
                mutex_.unlock();
                return false;
            }
            mutex_.unlock();
            // 获取结果集的行数
            int num_rows = mysql_num_rows(res);
            // 因为是查询一行，所以行数一定为1
            if(num_rows != 1)
            {
                std::cout << "have no data\n";
                mysql_free_result(res);
                return false;
            }

            // 获取结果集的内容
            MYSQL_ROW row = mysql_fetch_row(res);
            (*video)["id"] = video_id;
            (*video)["name"] = row[1];
            (*video)["info"] = row[2];
            (*video)["video"] = row[3];
            (*video)["image"] = row[4];
            
            // 自动释放内存
            mysql_free_result(res);
            return true;
        }
        
        // 对mysql进行模糊查询操作
        bool SelectLike(const std::string &key, Json::Value *videos)
        {
            #define SELECTLIKE_VIDEO "select * from tb_video where name like '%%%s%%';"
            char sql[1024] = {0};
            sprintf(sql, SELECTLIKE_VIDEO, key.c_str());
            // 保护查询与保存结果到本地的过程
            mutex_.lock();
            // 查询
            bool ret = MysqlQuery(mysql_, sql);
            if(ret == false)
            {
                mutex_.unlock();
                return false;
            }
            // 获取查询结果集
            MYSQL_RES *res = mysql_store_result(mysql_);
            if(res == nullptr)
            {
                std::cout << "mysql store result failed\n";
                mutex_.unlock();
                return false;
            }
            mutex_.unlock();
            // 获取结果集的行数
            int num_rows = mysql_num_rows(res);
            for(int i = 0; i < num_rows; ++i)
            {
                // 获取结果集的行内容
                MYSQL_ROW row = mysql_fetch_row(res);
                Json::Value video;
                video["id"] = atoi(row[0]);
                video["name"] = row[1];
                video["info"] = row[2];
                video["video"] = row[3];
                video["image"] = row[4];
                videos->append(video);
            }

            // 自动释放内存
            mysql_free_result(res);
            return true;
        }
    private:
        MYSQL *mysql_;     // mysql对象
        std::mutex mutex_; // 互斥锁
    };
}

#endif